bookwiz.io / app / books / [id] / page.tsx
page.tsx
Raw
'use client'

import { useState, useEffect, useRef, useCallback } from 'react'
import { useAuth } from '@/components/AuthProvider'
import { LoginButton } from '@/components/LoginButton'
import Editor from '@/components/Editor'
import ChatPanel from '@/components/ChatPanel'
import ResizablePanel from '@/components/ResizablePanel'
import { FileSystemItem } from '@/lib/types/database'
import { useFileSystem } from '@/lib/hooks/useFileSystem'
import { usePageLifecycle } from '@/lib/hooks/usePageLifecycle'
import { IoDocumentsOutline, IoSearchOutline, IoArrowBackOutline, IoGitBranchOutline, IoDocumentTextOutline, IoChatbubblesOutline, IoTimeOutline, IoSparklesOutline } from 'react-icons/io5'
import { useRouter } from 'next/navigation'
import ExplorerTab from '@/components/ExplorerTab'
import UnifiedSearchTab from '@/components/UnifiedSearchTab'
import DifferencesTab from '@/components/DifferencesTab'
import DownloadDropdown from '@/components/DownloadDropdown'
import DiffViewer from '@/components/DiffViewer'
import BookEditorSkeleton from '@/components/BookEditorSkeleton'


interface PageProps {
  params: {
    id: string
  }
}

interface BookInfo {
  id: string
  title: string
  description?: string
}

export default function BookEditor({ params }: PageProps) {
  const { user, loading: authLoading } = useAuth()
  const [selectedFile, setSelectedFile] = useState<FileSystemItem | null>(null)
  const [activeTab, setActiveTab] = useState<'explorer' | 'search' | 'differences'>('explorer')
  const [mobileView, setMobileView] = useState<'explorer' | 'editor' | 'assistant'>('explorer') // Mobile view state
  const [mobileTab, setMobileTab] = useState<'back' | 'explorer' | 'search' | 'differences'>('explorer') // Mobile tab state
  const [bookInfo, setBookInfo] = useState<BookInfo | null>(null)
  const [bookLoading, setBookLoading] = useState(true)
  const [initialFilesLoading, setInitialFilesLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [editorInstance, setEditorInstance] = useState<any>(null) // TipTap editor instance
  
  // Diff mode state
  const [showDiffMode, setShowDiffMode] = useState(false)
  const [diffInfo, setDiffInfo] = useState<{
    originalContent: string
    modifiedContent: string
    fileName: string
  } | null>(null)
  const router = useRouter()
  const lastVisibilityChangeRef = useRef<number>(Date.now())
  const isInitializedRef = useRef(false)
  const pageLifecycle = usePageLifecycle()
  
  // Check if device is mobile
  const isMobile = () => typeof window !== 'undefined' && window.innerWidth < 768
  
  const { 
    files, 
    loading: filesLoading, 
    error: filesError, 
    fetchFiles,
    updateItem,
    createItem,
    deleteItem,
    forceRefreshFiles
  } = useFileSystem()

  // Handle page visibility changes to prevent unnecessary reloads
  useEffect(() => {
    const handleVisibilityChange = () => {
      const now = Date.now()
      
      if (!document.hidden && document.visibilityState === 'visible') {
        // Page became visible
        if (pageLifecycle.shouldRefreshData()) {
          if (user && params.id && isInitializedRef.current) {
            fetchFiles(params.id)
          }
        }
      }
      
      lastVisibilityChangeRef.current = now
    }

    document.addEventListener('visibilitychange', handleVisibilityChange)
    return () => document.removeEventListener('visibilitychange', handleVisibilityChange)
  }, [user, params.id, fetchFiles, pageLifecycle])

  // Handle window resize for responsive layout
  useEffect(() => {
    const handleResize = () => {
      // On larger screens, ensure mobile view is reset
      if (!isMobile() && mobileView) {
        // Don't reset mobile view state, just let the responsive classes handle it
      }
    }

    window.addEventListener('resize', handleResize)
    return () => window.removeEventListener('resize', handleResize)
  }, [mobileView])

  const fetchFilesInitial = useCallback(async () => {
    setInitialFilesLoading(true)
    try {
      await fetchFiles(params.id)
    } finally {
      setInitialFilesLoading(false)
    }
  }, [params.id, fetchFiles])

  const fetchBookInfo = useCallback(async () => {
    try {
      setBookLoading(true)
      const response = await fetch(`/api/books?userId=${user?.id}`)
      
      if (!response.ok) {
        throw new Error('Failed to fetch book info')
      }
      
      const data = await response.json()
      const book = data.books?.find((b: any) => b.id === params.id)
      
      if (!book) {
        throw new Error('Book not found')
      }
      
      setBookInfo(book)
    } catch (error) {
      console.error('Error fetching book info:', error)
      setError(error instanceof Error ? error.message : 'Failed to load book')
    } finally {
      setBookLoading(false)
    }
  }, [user?.id, params.id])

  useEffect(() => {
    if (user && params.id && !isInitializedRef.current) {
      fetchBookInfo()
      fetchFilesInitial()
      isInitializedRef.current = true
    }
  }, [user, params.id, fetchBookInfo, fetchFilesInitial])

  const handleFileSelect = (file: FileSystemItem | null) => {
    setSelectedFile(file)
    // On mobile, switch to editor view when a file is selected
    if (file && file.type === 'file' && isMobile()) {
      setMobileView('editor')
    }
  }

  const handleFileContentChange = async (content: string) => {
    if (selectedFile && selectedFile.type === 'file') {
      try {
        await updateItem(params.id, selectedFile.id, { content })
      } catch (error) {
        console.error('Error saving file content:', error)
        // Could show an error toast here
      }
    }
  }

  const handleFileOperationComplete = useCallback(async () => {
    console.log('๐Ÿ”„ BookEditor: AI file operation completed, refreshing file system...')
    try {
      // Force refresh the file system (bypasses visibility checks and caching)
      await forceRefreshFiles()
      
      // Also refresh differences tab if it exists
      if ((window as any).refreshDifferencesTab) {
        (window as any).refreshDifferencesTab()
      }
      
      console.log('โœ… BookEditor: File system refresh completed')
    } catch (error) {
      console.error('โŒ BookEditor: Error refreshing files after AI operation:', error)
    }
  }, [forceRefreshFiles])

  const handleViewDiff = () => {
    console.log('๐Ÿ“– BookEditor: handleViewDiff called')
    
    // Check if we have diff info from the differences tab
    const currentDiffInfo = (window as any).currentDiffInfo
    if (currentDiffInfo) {
      console.log('๐Ÿ“– BookEditor: Found diff info, showing DiffViewer:', currentDiffInfo)
      setDiffInfo(currentDiffInfo)
      setShowDiffMode(true)
    } else {
      // Legacy: Trigger diff mode in the editor
      const editorToggleDiffMode = (window as any).editorToggleDiffMode
      if (editorToggleDiffMode && typeof editorToggleDiffMode === 'function') {
        console.log('๐Ÿ“– BookEditor: Calling editorToggleDiffMode')
        editorToggleDiffMode()
      } else {
        console.log('โŒ BookEditor: editorToggleDiffMode not available')
      }
    }
  }

  const handleCloseDiff = () => {
    console.log('๐Ÿ“– BookEditor: Closing diff mode')
    setShowDiffMode(false)
    setDiffInfo(null)
    // Clear the global diff info
    ;(window as any).currentDiffInfo = null
  }

  // Listen for close diff mode events from other components
  useEffect(() => {
    const handleCloseDiffEvent = () => {
      handleCloseDiff()
    }

    const handleFileOperationEvent = (event: CustomEvent) => {
      console.log('๐Ÿ“ BookEditor: File operation completed:', event.detail)
      // Trigger file system refresh
      handleFileOperationComplete()
    }
    
    const handleAIFileOperationEvent = (event: CustomEvent) => {
      console.log('๐Ÿค– BookEditor: AI file operation completed:', event.detail)
      // Trigger file system refresh after AI operations
      handleFileOperationComplete()
    }

    if (typeof window !== 'undefined') {
      window.addEventListener('close-diff-mode', handleCloseDiffEvent)
      window.addEventListener('file-operation-completed', handleFileOperationEvent as EventListener)
      window.addEventListener('ai-file-operation-completed', handleAIFileOperationEvent as EventListener)
      
      return () => {
        window.removeEventListener('close-diff-mode', handleCloseDiffEvent)
        window.removeEventListener('file-operation-completed', handleFileOperationEvent as EventListener)
        window.removeEventListener('ai-file-operation-completed', handleAIFileOperationEvent as EventListener)
      }
    }
  }, [handleFileOperationComplete])

  const handleEditorReady = (editor: any) => {
    setEditorInstance(editor)
  }

  // Auto-select last text file in root when files are first loaded
  useEffect(() => {
    if (files.length > 0 && !selectedFile && !initialFilesLoading) {
      // Find text files in the root level (no parent_id)
      const rootTextFiles = files.filter(file => 
        file.type === 'file' && 
        file.file_extension && 
        ['txt', 'md', 'markdown', 'html', 'htm', 'json'].includes(file.file_extension.toLowerCase())
      )
      
      if (rootTextFiles.length > 0) {
        // Select the last text file based on sort_order (highest sort_order = last)
        const lastTextFile = rootTextFiles.reduce((latest, current) => 
          (current.sort_order || 0) > (latest.sort_order || 0) ? current : latest
        )
        
        setSelectedFile(lastTextFile)
      }
    }
  }, [files, selectedFile, initialFilesLoading])

  // Check for GitHub OAuth data and switch to version control tab
  useEffect(() => {
    const urlParams = new URLSearchParams(window.location.search)
    const hasGitHubData = urlParams.get('repositories') && urlParams.get('accessToken') && urlParams.get('githubUsername')
    
    if (hasGitHubData && activeTab !== 'differences') {
      setActiveTab('differences')
    }
  }, [activeTab])

  // Update selectedFile when files tree changes
  useEffect(() => {
    if (selectedFile) {
      // Find the updated version of the currently selected file
      const findFileInTree = (files: (FileSystemItem & { children?: FileSystemItem[] })[], targetId: string): FileSystemItem | null => {
        for (const file of files) {
          if (file.id === targetId) {
            return file
          }
          if (file.children) {
            const found = findFileInTree(file.children, targetId)
            if (found) return found
          }
        }
        return null
      }

      const updatedFile = findFileInTree(files, selectedFile.id)
      if (updatedFile) {
        // Only update if the content has actually changed to prevent unnecessary re-renders
        const contentChanged = updatedFile.content !== selectedFile.content
        const nameChanged = updatedFile.name !== selectedFile.name
        
        if (contentChanged || nameChanged) {
          setSelectedFile(updatedFile)
        }
      }
    }
  }, [files, selectedFile, selectedFile?.id, selectedFile?.content, selectedFile?.name])

  const renderTabContent = () => {
    // Use mobileTab for mobile view, activeTab for desktop
    const currentTab = isMobile() ? mobileTab : activeTab
    
    switch (currentTab) {
      case 'explorer':
        return (
          <ExplorerTab
            files={files}
            onFileSelect={handleFileSelect}
            selectedFile={selectedFile}
            projectName={bookInfo?.title || 'Loading...'}
            bookId={params.id}
            createItem={createItem}
            updateItem={updateItem}
            deleteItem={deleteItem}
            loading={filesLoading}
          />
        )
      case 'search':
        return <UnifiedSearchTab bookId={params.id} onFileSelect={handleFileSelect} />
      case 'differences':
        return (
          <DifferencesTab
            bookId={params.id}
            onFileSelect={handleFileSelect}
            onRequestDiff={handleViewDiff}
          />
        )
      default:
        return null
    }
  }

  if (authLoading || bookLoading || initialFilesLoading) {
    return <BookEditorSkeleton />
  }

  if (!user) {
    return (
      <div className='h-screen flex items-center justify-center bg-slate-900'>
        <div className='max-w-md w-full bg-slate-800 rounded-lg shadow-lg p-8 text-center border border-slate-700'>
          <h1 className='text-2xl font-bold text-white mb-4'>
            Sign in Required
          </h1>
          <p className='text-slate-300 mb-6'>
            You need to sign in to access your book editor.
          </p>
          <LoginButton />
        </div>
      </div>
    )
  }

  if (error) {
    return (
      <div className='h-screen flex items-center justify-center bg-slate-900'>
        <div className='max-w-md w-full bg-slate-800 rounded-lg shadow-lg p-8 text-center border border-slate-700'>
          <h1 className='text-2xl font-bold text-red-400 mb-4'>
            Error Loading Book
          </h1>
          <p className='text-slate-300 mb-6'>{error}</p>
          <button
            onClick={() => router.push('/dashboard')}
            className='px-4 py-2 bg-slate-700 text-white rounded-md hover:bg-slate-600 transition-colors'
          >
            Back to Books
          </button>
        </div>
      </div>
    )
  }

  return (
    <div className='h-screen flex flex-col md:flex-row bg-black relative overflow-hidden book-editor-page'>
      {/* Simplified background for better performance */}
      <div className="absolute inset-0 bg-gradient-to-br from-black via-gray-950 to-black pointer-events-none" />
      
      {/* Reduced animated elements for better performance */}
      <div className="absolute inset-0 opacity-20 pointer-events-none">
        <div className="absolute top-0 left-1/4 w-64 h-64 bg-gradient-to-r from-blue-600/10 to-purple-600/10 rounded-full blur-2xl" />
        <div className="absolute bottom-0 right-1/4 w-64 h-64 bg-gradient-to-r from-purple-600/10 to-pink-600/10 rounded-full blur-2xl" />
      </div>

      {/* Desktop Layout - Three columns with resizable panels */}
      <div className="hidden md:flex w-full relative z-10">
        {/* Left Panel - File Explorer */}
        <ResizablePanel
          side="left"
          minWidth={200}
          maxWidth={500}
          defaultWidth={280}
          persistKey={`book_${params.id}_explorer`}
          className="bg-slate-900/60 border-r border-slate-700/50"
        >
          <div className="h-full flex flex-col">
            <div className='h-12 bg-slate-800/50 border-b border-slate-700/50'>
              <div className='grid grid-cols-4 h-12'>
                <button
                  className="flex items-center justify-center text-sm transition-all duration-200 relative group text-slate-400 hover:text-slate-200"
                  onClick={() => router.push('/dashboard')}
                >
                  <div className="absolute inset-0 bg-gradient-to-r from-blue-500/10 to-purple-500/10 rounded-lg transition-all duration-200 opacity-0 group-hover:opacity-100" />
                  <div className="relative">
                    <IoArrowBackOutline className='w-4 h-4' />
                  </div>
                </button>
                <button
                  className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
                    activeTab === 'explorer'
                      ? 'text-teal-400'
                      : 'text-slate-400 hover:text-slate-200'
                  }`}
                  onClick={() => {
                    setActiveTab('explorer')
                    setMobileTab('explorer')
                  }}
                >
                  <div className={`absolute inset-0 bg-gradient-to-r from-emerald-500/10 to-teal-500/10 rounded-lg transition-all duration-200 ${
                    activeTab === 'explorer' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
                  }`} />
                  <div className="relative">
                    <IoDocumentsOutline className='w-4 h-4' />
                  </div>
                </button>
                <button
                  className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
                    activeTab === 'search'
                      ? 'text-teal-400'
                      : 'text-slate-400 hover:text-slate-200'
                  }`}
                  onClick={() => {
                    setActiveTab('search')
                    setMobileTab('search')
                  }}
                >
                  <div className={`absolute inset-0 bg-gradient-to-r from-amber-500/10 to-orange-500/10 rounded-lg transition-all duration-200 ${
                    activeTab === 'search' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
                  }`} />
                  <div className="relative">
                    <IoSearchOutline className='w-4 h-4' />
                  </div>
                </button>
                <button
                  className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
                    activeTab === 'differences'
                      ? 'text-teal-400'
                      : 'text-slate-400 hover:text-slate-200'
                  }`}
                  onClick={() => {
                    setActiveTab('differences')
                    setMobileTab('differences')
                  }}
                >
                  <div className={`absolute inset-0 bg-gradient-to-r from-violet-500/10 to-purple-500/10 rounded-lg transition-all duration-200 ${
                    activeTab === 'differences' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
                  }`} />
                  <div className="relative">
                    <IoGitBranchOutline className='w-4 h-4' />
                  </div>
                </button>

              </div>
            </div>
            <div className="flex-1 overflow-y-auto">
              {renderTabContent()}
            </div>
          </div>
        </ResizablePanel>

        {/* Center Panel - Editor */}
        <div className='flex-1 flex flex-col min-w-0'>
          <div className='h-12 bg-slate-800/50 border-b border-slate-700/50 flex items-center px-4 justify-between'>
            {showDiffMode && diffInfo ? (
              // Diff mode header
              <>
                <div className="flex items-center gap-3">
                  <span className="text-sm text-teal-400 font-medium">โœจ</span>
                  <div className="text-sm text-slate-200 font-medium">
                    Changes in {diffInfo.fileName}
                  </div>
                  <div className="flex items-center gap-2 text-xs">
                    <span className="bg-slate-700/50 text-slate-400 px-2 py-1 rounded border border-slate-600/50">
                      Original
                    </span>
                    <span className="text-slate-500">vs</span>
                    <span className="bg-slate-700/50 text-slate-300 px-2 py-1 rounded border border-slate-600/50">
                      Modified
                    </span>
                  </div>
                </div>
                <button
                  onClick={handleCloseDiff}
                  className="bg-slate-700/50 hover:bg-slate-600/50 border border-slate-600/50 text-slate-300 hover:text-slate-200 px-2.5 py-1.5 rounded-md text-xs font-medium transition-all duration-150 flex items-center gap-1.5"
                >
                  <IoArrowBackOutline className="w-3.5 h-3.5" />
                  Back to Editor
                </button>
              </>
            ) : (
              // Normal mode header
              <>
                <span className='text-sm text-slate-300 font-medium'>
                  {selectedFile ? selectedFile.name : 'Select a file to edit'}
                </span>
                <div className="flex items-center gap-2">
                  {selectedFile && selectedFile.type === 'file' && (
                    <DownloadDropdown file={selectedFile} editor={editorInstance} />
                  )}
                  {selectedFile && selectedFile.type === 'file' && (
                    <span className='text-xs text-slate-400 bg-slate-700/50 px-2 py-1 rounded-md'>
                      {selectedFile.file_extension?.toUpperCase() || 'TXT'}
                    </span>
                  )}
                </div>
              </>
            )}
          </div>
          <div className='flex-1'>
            {showDiffMode && diffInfo ? (
              <DiffViewer
                originalContent={diffInfo.originalContent}
                modifiedContent={diffInfo.modifiedContent}
                fileName={diffInfo.fileName}
                className="h-full"
              />
            ) : (
              <Editor 
                file={selectedFile} 
                onContentChange={handleFileContentChange}
                bookId={params.id}
                onFileOperationComplete={handleFileOperationComplete}
                onDiffModeRequest={handleViewDiff}
                onEditorReady={handleEditorReady}
              />
            )}
          </div>
        </div>

        {/* Right Panel - Chat */}
        <ResizablePanel
          side="right"
          minWidth={300}
          maxWidth={700}
          defaultWidth={450}
          persistKey={`book_${params.id}_chat`}
          className="bg-slate-800/60 border-l border-slate-700/50"
        >
          <ChatPanel 
            bookId={params.id} 
            onFileOperationComplete={handleFileOperationComplete}
            onViewDiff={handleViewDiff}
            onFileSelect={handleFileSelect}
          />
        </ResizablePanel>
      </div>

      {/* Mobile Layout - Single column with bottom navigation */}
      <div className="flex-1 flex md:hidden flex-col relative z-10 overflow-hidden">
        {/* Mobile view content */}
        {mobileView === 'explorer' && (
          <div className="flex-1 bg-slate-800/60 flex flex-col min-h-0">
            <div className='h-12 bg-slate-800/50 border-b border-slate-700/50'>
              <div className='grid grid-cols-4 h-12'>
                <button
                  className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
                    mobileTab === 'back'
                      ? 'text-teal-400'
                      : 'text-slate-400 hover:text-slate-200'
                  }`}
                  onClick={() => router.push('/dashboard')}
                >
                  <div className={`absolute inset-0 bg-gradient-to-r from-blue-500/10 to-purple-500/10 rounded-lg transition-all duration-200 ${
                    mobileTab === 'back' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
                  }`} />
                  <div className="relative">
                    <IoArrowBackOutline className='w-4 h-4' />
                  </div>
                </button>
                <button
                  className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
                    mobileTab === 'explorer'
                      ? 'text-teal-400'
                      : 'text-slate-400 hover:text-slate-200'
                  }`}
                  onClick={() => {
                    setMobileTab('explorer')
                    setActiveTab('explorer')
                  }}
                >
                  <div className={`absolute inset-0 bg-gradient-to-r from-emerald-500/10 to-teal-500/10 rounded-lg transition-all duration-200 ${
                    mobileTab === 'explorer' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
                  }`} />
                  <div className="relative">
                    <IoDocumentsOutline className='w-4 h-4' />
                  </div>
                </button>
                <button
                  className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
                    mobileTab === 'search'
                      ? 'text-teal-400'
                      : 'text-slate-400 hover:text-slate-200'
                  }`}
                  onClick={() => {
                    setMobileTab('search')
                    setActiveTab('search')
                  }}
                >
                  <div className={`absolute inset-0 bg-gradient-to-r from-amber-500/10 to-orange-500/10 rounded-lg transition-all duration-200 ${
                    mobileTab === 'search' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
                  }`} />
                  <div className="relative">
                    <IoSearchOutline className='w-4 h-4' />
                  </div>
                </button>
                <button
                  className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
                    mobileTab === 'differences'
                      ? 'text-teal-400'
                      : 'text-slate-400 hover:text-slate-200'
                  }`}
                  onClick={() => {
                    setMobileTab('differences')
                    setActiveTab('differences')
                  }}
                >
                  <div className={`absolute inset-0 bg-gradient-to-r from-violet-500/10 to-purple-500/10 rounded-lg transition-all duration-200 ${
                    mobileTab === 'differences' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
                  }`} />
                  <div className="relative">
                    <IoGitBranchOutline className='w-4 h-4' />
                  </div>
                </button>
              </div>
            </div>
            <div className="flex-1 overflow-y-auto min-h-0">
              {renderTabContent()}
            </div>
          </div>
        )}

        {mobileView === 'editor' && (
          <div className="flex-1 flex flex-col">
            <div className='h-12 bg-slate-800/50 border-b border-slate-700/50 flex items-center px-4 justify-between'>
              {showDiffMode && diffInfo ? (
                // Diff mode header
                <>
                  <div className="flex items-center gap-2">
                    <span className="text-sm text-teal-400 font-medium">โœจ</span>
                    <div className="text-sm text-slate-200 font-medium">
                      Changes in {diffInfo.fileName}
                    </div>
                  </div>
                  <button
                    onClick={handleCloseDiff}
                    className="bg-slate-700/50 hover:bg-slate-600/50 border border-slate-600/50 text-slate-300 hover:text-slate-200 px-2 py-1 rounded-md text-xs font-medium transition-all duration-150 flex items-center gap-1"
                  >
                    <IoArrowBackOutline className="w-3 h-3" />
                    Back
                  </button>
                </>
              ) : (
                // Normal mode header
                <>
                  <span className='text-sm text-slate-300 font-medium'>
                    {selectedFile ? selectedFile.name : 'Select a file to edit'}
                  </span>
                  <div className="flex items-center gap-2">
                    {selectedFile && selectedFile.type === 'file' && (
                      <DownloadDropdown file={selectedFile} editor={editorInstance} />
                    )}
                    {selectedFile && selectedFile.type === 'file' && (
                      <span className='text-xs text-slate-400 bg-slate-700/50 px-2 py-1 rounded-md'>
                        {selectedFile.file_extension?.toUpperCase() || 'TXT'}
                      </span>
                    )}
                  </div>
                </>
              )}
            </div>
            <div className='flex-1'>
              {showDiffMode && diffInfo ? (
                <DiffViewer
                  originalContent={diffInfo.originalContent}
                  modifiedContent={diffInfo.modifiedContent}
                  fileName={diffInfo.fileName}
                  className="h-full"
                />
              ) : (
                <Editor 
                  file={selectedFile} 
                  onContentChange={handleFileContentChange}
                  bookId={params.id}
                  onFileOperationComplete={handleFileOperationComplete}
                  onDiffModeRequest={handleViewDiff}
                  onEditorReady={handleEditorReady}
                />
              )}
            </div>
          </div>
        )}

        {/* Always render ChatPanel to preserve streaming state, but control visibility */}
        <div className={`flex-1 flex flex-col min-h-0 overflow-hidden ${
          mobileView === 'assistant' ? 'block' : 'hidden'
        }`}>
          <ChatPanel 
            bookId={params.id} 
            onFileOperationComplete={handleFileOperationComplete}
            onViewDiff={handleViewDiff}
            onFileSelect={handleFileSelect}
          />
        </div>

        {/* Mobile Bottom Navigation */}
        <div className="h-12 bg-slate-900/95 border-t border-slate-700/60 flex items-center justify-around px-2">
          <button
            className={`flex items-center justify-center py-2 px-4 rounded-xl transition-all duration-200 relative group ${
              mobileView === 'explorer'
                ? 'text-teal-400 bg-teal-500/15 shadow-lg shadow-teal-500/10'
                : 'text-slate-400 hover:text-slate-200 hover:bg-slate-700/40'
            }`}
            onClick={() => setMobileView('explorer')}
          >
            <div className="flex items-center gap-2">
              <IoDocumentsOutline className={`w-4 h-4 ${mobileView === 'explorer' ? 'text-teal-400' : ''}`} />
              <span className="text-xs font-medium">Files</span>
            </div>
            {mobileView === 'explorer' && (
              <div className="absolute inset-0 bg-gradient-to-r from-teal-500/10 to-cyan-500/10 rounded-xl" />
            )}
          </button>
          <button
            className={`flex items-center justify-center py-2 px-4 rounded-xl transition-all duration-200 relative group ${
              mobileView === 'editor'
                ? 'text-teal-400 bg-teal-500/15 shadow-lg shadow-teal-500/10'
                : 'text-slate-400 hover:text-slate-200 hover:bg-slate-700/40'
            }`}
            onClick={() => setMobileView('editor')}
          >
            <div className="flex items-center gap-2">
              <IoDocumentTextOutline className={`w-4 h-4 ${mobileView === 'editor' ? 'text-teal-400' : ''}`} />
              <span className="text-xs font-medium">Editor</span>
            </div>
            {mobileView === 'editor' && (
              <div className="absolute inset-0 bg-gradient-to-r from-teal-500/10 to-cyan-500/10 rounded-xl" />
            )}
          </button>
          <button
            className={`flex items-center justify-center py-2 px-4 rounded-xl transition-all duration-200 relative group ${
              mobileView === 'assistant'
                ? 'text-teal-400 bg-teal-500/15 shadow-lg shadow-teal-500/10'
                : 'text-slate-400 hover:text-slate-200 hover:bg-slate-700/40'
            }`}
            onClick={() => setMobileView('assistant')}
          >
            <div className="flex items-center gap-2">
              <IoChatbubblesOutline className={`w-4 h-4 ${mobileView === 'assistant' ? 'text-teal-400' : ''}`} />
              <span className="text-xs font-medium">Chat</span>
            </div>
            {mobileView === 'assistant' && (
              <div className="absolute inset-0 bg-gradient-to-r from-teal-500/10 to-cyan-500/10 rounded-xl" />
            )}
          </button>
        </div>
      </div>
    </div>
  )
}